package com.suyafei.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.suyafei.config.RabbitMQConfig;
import com.suyafei.enums.BizCodeEnum;
import com.suyafei.enums.ProductOrderStateEnum;
import com.suyafei.enums.StockTaskStateEnum;
import com.suyafei.exception.BizException;
import com.suyafei.feign.ProductOrderFeignService;
import com.suyafei.mapper.ProductMapper;
import com.suyafei.mapper.ProductTaskMapper;
import com.suyafei.model.ProductDO;
import com.suyafei.model.ProductMessage;
import com.suyafei.model.ProductTaskDO;
import com.suyafei.request.LockProductRequest;
import com.suyafei.request.OrderItemRequest;
import com.suyafei.service.ProductService;
import com.suyafei.util.JsonData;
import com.suyafei.vo.ProductVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author suyafei
 * @since 2021-03-08
 */
@Slf4j
@Service
public class ProductServiceImpl implements ProductService {

    @Autowired
    private ProductOrderFeignService feignService;
    @Autowired
    private ProductTaskMapper productTaskMapper;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private ProductMapper productMapper;
    @Autowired
    private RabbitMQConfig rabbitMQConfig;
    /**
     * 分页查询商品信息
     * @param page
     * @param size
     * @return
     */
    @Override
    public Map<String, Object> page(int page, int size) {


        Page<ProductDO> pageInfo = new Page<>();

        IPage<ProductDO> productDOIPage = productMapper
                .selectPage(pageInfo, new QueryWrapper<ProductDO>().orderByAsc("create_time"));

        Map<String, Object> productMap = new HashMap<>();

        productMap.put("total_record", productDOIPage.getTotal());
        productMap.put("total_page", productDOIPage.getPages());
        productMap.put("current_data", productDOIPage.getRecords().stream().map(obj -> beanProcess(obj)).collect(Collectors.toList()));
        return productMap;
    }


    /**
     * 释放商品库存
     *
     * @param productMessage
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean releaseProductStock(ProductMessage productMessage) {

        ProductTaskDO taskDO = productTaskMapper.selectOne(new QueryWrapper<ProductTaskDO>().eq("id", productMessage.getTaskId()));


        if (taskDO == null
        ) {
            log.warn("工作单不存在，消息体为{}", productMessage);
            return true;
        }
        //lock状态才处理
        if (taskDO.getLockState().equalsIgnoreCase(StockTaskStateEnum.LOCK.name())) {

            JsonData jsonData = feignService.queryProductOrderState(taskDO.getOutTradeNo());
            if (jsonData==null) {
                log.error("jsonData为空");
            }
            if (jsonData.getCode() == 0) {
                String state = jsonData.getData().toString();
                if (state.equalsIgnoreCase(ProductOrderStateEnum.NEW.name())) {
                    log.info("订单装填为new，重新装填队列{}", productMessage);
                    return false;
                }
                if (state.equalsIgnoreCase(ProductOrderStateEnum.PAY.name())) {
                    taskDO.setLockState(StockTaskStateEnum.FINISH.name());
                    productTaskMapper.update(taskDO, new QueryWrapper<ProductTaskDO>().eq("id", taskDO.getId()));
                    log.info("工作单处理完成,更新TaskDO为FINISH状态{}", taskDO.toString());
                    return true;
                }
            }
            log.warn("订单不存在，或者订单被取消，确认消息,修改task状态为CANCEL，恢复库存，message{}", productMessage);
            taskDO.setLockState(StockTaskStateEnum.CANCEL.name());
            log.info("修改工作单位CANCEL{}",productMessage);
            productTaskMapper.update(taskDO, new QueryWrapper<ProductTaskDO>().eq("id", taskDO.getId()));
            log.info("释放库存{}",taskDO.getBuyNum());
            productMapper.releaseProductStock(taskDO.getProductId(), taskDO.getBuyNum());
            return true;

        }else {
            log.warn("工作单状态不是LOCK，state状态为：{},消息={}", taskDO.getLockState(), productMessage);
            return true;
        }
    }

    /**
     * 锁定商品库存
     *
     * 1.遍历商品，锁定每个商品购买的数量
     * 2.每一次锁定的时候，都要发送延迟消息
     *  @param lockProductRequest
     */
    @Override
    public void lockProductStock(LockProductRequest lockProductRequest) {


        String outTradeNo = lockProductRequest.getOrderOutTradeNo();
        List<OrderItemRequest> itemList = lockProductRequest.getOrderItemList();

        //提取对象里面的id加入到集合里面
        List<Long> productIds = itemList.stream().map(OrderItemRequest::getProductId).collect(Collectors.toList());

        //批量查询
        List<ProductVO> productVOList = this.findProductByIdBatch(productIds);

        Map<Long, ProductVO> productMap = productVOList.stream().collect(Collectors.toMap(ProductVO::getId, Function.identity()));

        for (OrderItemRequest orderItemRequest : itemList) {

            int rows = productMapper.lockProductStock(orderItemRequest.getProductId(), orderItemRequest.getBuyNum());
            if (rows != 1) {
                throw new BizException(BizCodeEnum.ORDER_CONFIRM_LOCK_PRODUCT_FAIL);
            }else {
                // 插入商品的task
                ProductVO productVO = productMap.get(orderItemRequest.getProductId());
                ProductTaskDO productTaskDO = new ProductTaskDO();

                productTaskDO.setProductId(orderItemRequest.getProductId());
                productTaskDO.setLockState(StockTaskStateEnum.LOCK.name());
                productTaskDO.setOutTradeNo(outTradeNo);
                productTaskDO.setProductName(productVO.getTitle());
                productTaskDO.setBuyNum(orderItemRequest.getBuyNum());
                productTaskMapper.insert(productTaskDO);
                log.info("商品库存锁定信息插入成功{}",productTaskDO.toString());

                //发送延迟MQ延迟消息，介绍商品库存 TODO
                ProductMessage productMessage = new ProductMessage();
                productMessage.setOutTradeNo(outTradeNo);
                productMessage.setTaskId(productTaskDO.getId());

                rabbitTemplate.convertAndSend(rabbitMQConfig.getEventExchange(),rabbitMQConfig.getStockReleaseDelayRoutingKey(),productMessage);
                log.info("商品库存锁定信息延迟消息发送成功{}",productMessage);


            }

        }
    }

    /**
     * 根据Id批量查询商品
     *
     * @param productIdList
     * @return
     */
    @Override
    public List<ProductVO> findProductByIdBatch(List<Long> productIdList) {

        List<ProductDO> productDOList = productMapper.selectList(new QueryWrapper<ProductDO>().in("id", productIdList));
        List<ProductVO> productVOList = productDOList.stream().map(obj -> beanProcess(obj)).collect(Collectors.toList());
        return productVOList;
    }

    /**
     * 根据ID查找商品
     * @param productId
     * @return
     */
    @Override
    public ProductVO findDetailById(long productId) {

        ProductDO productDO = productMapper.selectById(productId);

        return beanProcess(productDO);
    }

    private ProductVO beanProcess(ProductDO productDO) {
        ProductVO productVO = new ProductVO();
        BeanUtils.copyProperties(productDO, productVO);
        productVO.setStock(productDO.getStock()-productDO.getLockStock());
        return productVO;
    }
}
